package com.piggy.logi.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.piggy.common.core.exception.base.BaseException;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.common.satoken.utils.SecurityUtils;
import com.piggy.logi.sys.bo.LogiDrayageExtEditBo;
import com.piggy.logi.sys.bo.LogiDrayageQueryBo;
import com.piggy.logi.sys.bo.LogiWaybillQueryBo;
import com.piggy.logi.sys.domain.LogiDrayage;
import com.piggy.logi.sys.domain.LogiWaybill;
import com.piggy.logi.sys.enums.DrayageStatusEnum;
import com.piggy.logi.sys.mapper.LogiDrayageMapper;
import com.piggy.logi.sys.service.*;
import com.piggy.logi.sys.vo.LogiCarrierCarExtVo;
import com.piggy.logi.sys.vo.LogiCarrierDriverExtVo;
import com.piggy.logi.sys.vo.LogiDrayageExtVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 短驳车次信息Service业务层处理
 *
 * @author piggy
 * @date 2023-09-18
 */
@Slf4j
@Service
public class LogiDrayageServiceImpl extends ServiceImpl<LogiDrayageMapper, LogiDrayage> implements ILogiDrayageService {

    @Resource
    private ILogiWaybillService logiWaybillService;

    @Resource
    private ILogiSysDeptService deptService;

    @Resource
    private ILogiCarrierDriverService driverService;

    @Resource
    private ILogiCarrierCarService carService;
    @Resource
    private ILogiSysBaseConfigService logiSysBaseConfigService;


    @Override
    public LogiDrayageExtVo queryById(Long drayageId) {
        LogiDrayageExtVo vo = getVoById(drayageId, LogiDrayageExtVo.class);
        if (ObjectUtil.isEmpty(vo)) {
            return vo;
        }

        return fillData(Lists.newArrayList(vo), false).get(0);
    }

    @Override
    public TableDataInfo<LogiDrayageExtVo> queryPageList(LogiDrayageQueryBo bo) {
        bo.setDeptId(SecurityUtils.getDeptId());
        PageInfo<LogiDrayageExtVo> result = startPage(bo).doSelectPageInfo(() -> {
            List<LogiDrayageExtVo> voList = baseMapper.selectDRYList(buildQueryWrapper(bo));
            fillData(voList, false);
        });
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiDrayageExtVo> queryList(LogiDrayageQueryBo bo, boolean ignoreWaybill) {
        bo.setDeptId(SecurityUtils.getDeptId());
        return fillData(baseMapper.selectDRYList(buildQueryWrapper(bo)), ignoreWaybill);
    }

    @Override
    public List<LogiDrayageExtVo> queryList(LogiDrayageQueryBo bo) {
        return queryList(bo, false);
    }

    private QueryWrapper<LogiDrayage> buildQueryWrapper(LogiDrayageQueryBo bo) {
        QueryWrapper<LogiDrayage> lqw = Wrappers.query();
        lqw.eq(bo.getDrayageId() != null, "dry.drayage_id", bo.getDrayageId());
        lqw.eq(bo.getDeptId() != null, "dry.dept_id",bo.getDeptId());
        lqw.eq(StrUtil.isNotBlank(bo.getDrayageNo()), "dry.drayage_no", bo.getDrayageNo());
        lqw.eq(bo.getDriverId() != null, "dry.driver_id", bo.getDriverId());
        lqw.eq(StrUtil.isNotBlank(bo.getDriverJson()), "dry.driver_json", bo.getDriverJson());
        lqw.eq(bo.getCarId() != null, "dry.car_id", bo.getCarId());
        lqw.eq(StrUtil.isNotBlank(bo.getCarJson()), "dry.car_json", bo.getCarJson());
        lqw.eq(bo.getDepDeptId() != null, "dry.dep_dept_id", bo.getDepDeptId());
        lqw.eq(bo.getDesDeptId() != null, "dry.des_dept_id", bo.getDesDeptId());
        lqw.eq(bo.getDepartTime() != null, "dry.depart_time", bo.getDepartTime());
        lqw.eq(bo.getArriveTime() != null, "dry.arrive_time", bo.getArriveTime());
        lqw.between(ObjectUtil.isAllNotEmpty(bo.getStartTime(),bo.getEndTime()), "dry.create_time", bo.getStartTime(), bo.getEndTime());
        lqw.eq(ObjectUtil.isNotEmpty(bo.getDrayageStatus()), "dry.drayage_status", bo.getDrayageStatus());
        lqw.in(CollUtil.isNotEmpty(bo.getDrayageNos()), "dry.drayage_no", bo.getDrayageNos());
        lqw.in(CollUtil.isNotEmpty(bo.getDrayageList()), "dry.drayage_status", bo.getDrayageList());
        lqw.apply(ObjectUtil.isAllNotEmpty(bo.getCreateTimeStart(), bo.getCreateTimeEnd()), "date_format(dry.create_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') " , bo.getCreateTimeStart(), bo.getCreateTimeEnd());
        lqw = lqw.apply(StrUtil.isNotBlank(bo.getCarJson()), "(FIND_IN_SET ('"+bo.getCarJson()+"',dry.car_json)");
        lqw = lqw.apply(StrUtil.isNotBlank(bo.getDriverJson()), "(FIND_IN_SET ('"+bo.getDriverJson()+"',dry.driver_json)");

        lqw.like(StrUtil.isNotBlank(bo.getOutCode()), "bill.out_code", bo.getOutCode());
        return lqw;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LogiDrayageExtVo insertByAddBo(LogiDrayageExtEditBo bo) {
        if (CollUtil.isEmpty(bo.getWaybillIds())) {
            throw new BaseException("发车是需要运单ID记录,当前数据 = "+JSON.toJSONString(bo.getWaybillIds()));
        }
        bo.setDeptId(SecurityUtils.getDeptId());
        bo.setDrayageStatus(DrayageStatusEnum.DEPARTURE.getCode());
//        String date = DateUtil.format(new Date(), "yyyyMMdd");
//        String key = CacheKeyEnums.LogiDrayageNo.getKey(date);
//        if (!CacheUtils.hasKey(key)) {
//            CacheUtils.cache(0, key, 2L, TimeUnit.DAYS);
//        }
//        Long no = CacheUtils.incrBy(key);
//        bo.setDrayageNo(String.format("%s%s%06d", BizNoPrefixEnum.DRAYAGE_NO.getCode(), date, no));
        bo.setDrayageNo(logiSysBaseConfigService.getDrayageNo(bo.getDeptId()));
        LogiDrayage add = BeanUtil.toBean(bo, LogiDrayage.class);
        add.setDriverJson(JSON.toJSONString(bo.getDriverJson()));
        add.setDriverId(bo.getDriverJson().getDriverId());
        add.setCarJson(JSON.toJSONString(bo.getCarJson()));
        add.setCarId(bo.getCarJson().getCarId());

        add.setDriverJson(JSON.toJSONString(bo.getDriverJson()));
        add.setCarJson(JSON.toJSONString(bo.getCarJson()));

        LogiCarrierCarExtVo carExtVo = carService.queryById(add.getCarId());
        if (ObjectUtil.isNotEmpty(carExtVo)) {
            BeanUtil.copyProperties(bo.getCarJson(), carExtVo, CopyOptions.create().ignoreNullValue());
            add.setCarJson(JSON.toJSONString(carExtVo));
        }
        LogiCarrierDriverExtVo driverExtVo = driverService.queryById(add.getDriverId());
        if (ObjectUtil.isNotEmpty(driverExtVo)) {
            BeanUtil.copyProperties(add.getDriverJson(), driverExtVo, CopyOptions.create().ignoreNullValue());
            add.setDriverJson(JSON.toJSONString(driverExtVo));
        }

        add.setCreateBy(SecurityUtils.getPhone());
        add.setCreateTime(new Date());
        add.setDepartTime(new Date());
        save(add);
        LogiDrayage vo = getById(add.getDrayageId());

        if (CollUtil.isNotEmpty(bo.getWaybillIds())) {
            LambdaUpdateWrapper<LogiWaybill> updateWrapper = Wrappers.lambdaUpdate();
            bo.getWaybillIds().add("0");
            updateWrapper.set(LogiWaybill::getDrayageNo, vo.getDrayageNo())
                    .set(LogiWaybill::getDrayageStatus, vo.getDrayageStatus())
                    .in(LogiWaybill::getWaybillId, bo.getWaybillIds().stream().map(Long::valueOf).collect(Collectors.toList()));
            logiWaybillService.update(updateWrapper);
        }

        return queryById(add.getDrayageId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LogiDrayageExtVo updateByEditBo(LogiDrayageExtEditBo bo) {
        LogiDrayage update = BeanUtil.toBean(bo, LogiDrayage.class);

        update.setDriverJson(JSON.toJSONString(bo.getDriverJson()));
        update.setCarJson(JSON.toJSONString(bo.getCarJson()));

        LogiCarrierCarExtVo carExtVo = carService.queryById(update.getCarId());
        if (ObjectUtil.isNotEmpty(carExtVo)) {
            BeanUtil.copyProperties(bo.getCarJson(), carExtVo, CopyOptions.create().ignoreNullValue());
            update.setCarJson(JSON.toJSONString(carExtVo));
        }
        LogiCarrierDriverExtVo driverExtVo = driverService.queryById(update.getDriverId());
        if (ObjectUtil.isNotEmpty(driverExtVo)) {
            BeanUtil.copyProperties(update.getDriverJson(), driverExtVo, CopyOptions.create().ignoreNullValue());
            update.setDriverJson(JSON.toJSONString(driverExtVo));
        }

        update.setUpdateBy(SecurityUtils.getPhone());
        update.setUpdateTime(new Date());
        updateById(update);

        LogiDrayage vo = getById(update.getDrayageId());

        if (CollUtil.isNotEmpty(bo.getWaybillIds())) {
            LambdaUpdateWrapper<LogiWaybill> updateWrapper = Wrappers.lambdaUpdate();
            bo.getWaybillIds().add("0");
            updateWrapper.set(LogiWaybill::getDrayageNo, vo.getDrayageNo())
                    .set(LogiWaybill::getDrayageStatus, vo.getDrayageStatus())
                    .in(LogiWaybill::getWaybillId, bo.getWaybillIds().stream().map(Long::valueOf).collect(Collectors.toList()));
            logiWaybillService.update(updateWrapper);
        }

        return queryById(update.getDrayageId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return removeByIds(ids);
    }

    private List<LogiDrayageExtVo> fillData(List<LogiDrayageExtVo> recordVos, boolean ignoreWaybill) {
        if (CollUtil.isEmpty(recordVos)) {
            return recordVos;
        }

        return recordVos.stream().peek(vo -> {
            vo.setDriverVo(JSON.parseObject(vo.getDriverJson(), LogiCarrierDriverExtVo.class));
            vo.setCarVo(JSON.parseObject(vo.getCarJson(), LogiCarrierCarExtVo.class));

            /*LogiCarrierDriverExtVo driverExtVo = driverService.queryById(vo.getDriverId());
            LogiCarrierCarExtVo carExtVo = carService.queryById(vo.getCarId());
            vo.setDriverVo(JSON.parseObject(vo.getDriverJson(), LogiCarrierDriverExtVo.class));
            if (ObjectUtil.isNotEmpty(driverExtVo)) {
                BeanUtil.copyProperties(vo.getDriverVo(), driverExtVo, CopyOptions.create().ignoreNullValue());
                vo.setDriverVo(driverExtVo);
            }

            vo.setCarVo(JSON.parseObject(vo.getCarJson(), LogiCarrierCarExtVo.class));
            if (ObjectUtil.isNotEmpty(carExtVo)) {
                BeanUtil.copyProperties(vo.getCarVo(), carExtVo, CopyOptions.create().ignoreNullValue());
                vo.setCarVo(carExtVo);
            }*/

            if (!ignoreWaybill) {
                LogiWaybillQueryBo queryBo = new LogiWaybillQueryBo();
                queryBo.setDrayageNo(vo.getDrayageNo());
                queryBo.setDeptId(SecurityUtils.getDeptId());
                vo.setWaybillList(logiWaybillService.queryList(queryBo));
            }
            vo.setDepDeptVo(deptService.selectDeptById(vo.getDepDeptId()));
            vo.setDesDeptVo(deptService.selectDeptById(vo.getDesDeptId()));
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LogiDrayageExtVo updateStatus(String drayageNo, Integer drayageStatus) {

        LambdaUpdateWrapper<LogiDrayage> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(LogiDrayage::getDrayageStatus, drayageStatus)
                .set(LogiDrayage::getUpdateBy, SecurityUtils.getPhone())
                .set(LogiDrayage::getUpdateTime, new Date())
                .eq(LogiDrayage::getDrayageNo, drayageNo);
        if (drayageStatus == DrayageStatusEnum.DEPARTURE.getCode()) {
            updateWrapper.set(LogiDrayage::getArriveTime, null);
        }
        if (drayageStatus == DrayageStatusEnum.RECEIVED.getCode()) {
            updateWrapper.set(LogiDrayage::getArriveTime, new Date());
        }
        if (drayageStatus == DrayageStatusEnum.CANCEL.getCode()) {
            updateWrapper.set(LogiDrayage::getDepartTime, null);
            updateWrapper.set(LogiDrayage::getArriveTime, null);
        }
        update(null, updateWrapper);

        logiWaybillService.updateDrayageStatus(drayageNo, drayageStatus);

        return queryById(baseMapper.findByUk(drayageNo).getDrayageId());
    }
}
